﻿
namespace Sai.Test.Rules
{
    using NSubstitute;
    using Sai.Core;
    using Sai.Core.Rules;
    using Sai.Test.TestDataBuilders;
    using Sai.Test.XUnit;
    using System.Linq;
    using Xunit;

	public class CheckConstantValuesFacts
	{
        [Fact, TouchingFileSystemTest]
        public void Constant_In_Both_Versions_Shows_Zero_Changes()
        {
            const string className = "Class1";
            const string namespaceName = "ClassLibrary1";
            const string field = "public const int MyConstant = 999;";

            string oldCode = BoilerPlateCodeBuilder.BuildFor(namespaceName, 
                                    CompilableClassBuilder.PublicClass()
                                                        .Named(className)
                                                        .WithConstant(field));

            string newCode = BoilerPlateCodeBuilder.BuildFor(namespaceName, 
                                    CompilableClassBuilder.PublicClass()
                                                        .Named(className)
                                                        .WithConstant(field));

            IProductReleaseProject project = Mock.MinimalProject();

            TypeDifference diff = TypeDifferenceBuilder.Differences()
                .CodeWas(oldCode)
                .CodeIsNow(newCode)
                .CheckedUsing(new CheckConstantValues())
                .Build();

            Assert.False(diff.HasChanged);

            Assert.Null(diff.ConstantsAdded);
            Assert.Null(diff.ConstantsChanged);
            Assert.Null(diff.ConstantsObsolete);
            Assert.Null(diff.ConstantsRemoved);
        }

		
		[Fact, TouchingFileSystemTest]
		public void Removing_Constant_From_Class_Is_Flagged()
		{
            const string className = "Class1";
            const string intConstant = "public const int MY_CONSTANT = 2;";

            var oldClassBuilder = CompilableClassBuilder.PublicClass()
                                                    .Named(className)
                                                    .WithConstant(intConstant);

			string oldCode = BoilerPlateCodeBuilder.BuildFor(oldClassBuilder);

            var newClassBuilder = CompilableClassBuilder.PublicClass()
                                                    .Named(className);

            string newCode = BoilerPlateCodeBuilder.BuildFor(newClassBuilder);

            IProductReleaseProject project = Mock.MinimalProject();

			TypeDifference diff = TypeDifferenceBuilder.Differences()
                .CodeWas(oldCode)
                .CodeIsNow(newCode)
                .CheckedUsing(new CheckConstantValues())
                .Build();

			Assert.True(diff.HasChanged);

            Assert.Equal(1, diff.ConstantsRemoved.Count);
            Assert.Equal(TypeChangeReason.ConstantRemoved, diff.ConstantsRemoved.First().Reason);
		}

        
        [Fact, TouchingFileSystemTest]
        public void Adding_Constant_To_Class_Is_Flagged()
        {
            const string className = "Class1";
            const string intConstant = "public const int MY_CONSTANT = 2;";

            var oldClassBuilder = CompilableClassBuilder.PublicClass()
                                                    .Named(className);

            string oldCode = BoilerPlateCodeBuilder.BuildFor(oldClassBuilder);

            var newClassBuilder = CompilableClassBuilder.PublicClass()
                                                    .Named(className)
                                                    .WithConstant(intConstant);

            string newCode = BoilerPlateCodeBuilder.BuildFor(newClassBuilder);

            IProductReleaseProject project = Mock.MinimalProject();

            TypeDifference diff = TypeDifferenceBuilder.Differences()
                .CodeWas(oldCode)
                .CodeIsNow(newCode)
                .CheckedUsing(new CheckConstantValues())
                .Build();

            Assert.True(diff.HasChanged);

            Assert.Equal(1, diff.ConstantsAdded.Count);
            Assert.Equal(TypeChangeReason.ConstantAdded, diff.ConstantsAdded.First().Reason);
        }

        
        [Fact, TouchingFileSystemTest]
        public void Changing_Constant_Type_Is_Flagged()
        {
            const string className = "Class1";
            const string intConstant = "public const int MY_CONSTANT = 2;";

            var oldClassBuilder = CompilableClassBuilder.PublicClass()
                                                    .Named(className)
                                                    .WithConstant(intConstant);

            string oldCode = BoilerPlateCodeBuilder.BuildFor(oldClassBuilder);

            const string stringConstant = "public const string MY_CONSTANT = \"Hello World\";";

            var newClassBuilder = CompilableClassBuilder.PublicClass()
                                                    .Named(className)
                                                    .WithConstant(stringConstant);

            string newCode = BoilerPlateCodeBuilder.BuildFor(newClassBuilder);

            IProductReleaseProject project = Mock.MinimalProject();

            TypeDifference diff = TypeDifferenceBuilder.Differences()
                .CodeWas(oldCode)
                .CodeIsNow(newCode)
                .CheckedUsing(new CheckConstantValues())
                .Build();

            Assert.True(diff.HasChanged);

            Assert.Equal(1, diff.ConstantsChanged.Count);
            Assert.Equal(TypeChangeReason.ConstantChanged, diff.ConstantsChanged.First().Reason);
        }

    }
}
